<template>
  <el-form
    ref="ruleFormRef"
    :model="ruleForm"
    :rules="rules"
    class="demo-ruleForm"
    :class="{ fhlrw: config?.horizontallyWidth, fhlw: config?.multiLine }"
    :size="formSize"
    :label-position="config?.labelPosition"
    :style="{ width: config?.formWidth || 'auto' }"
  >
    <template v-for="(items, index) in formList" :key="items.prop">
      <el-form-item
        v-if="!items.hidden"
        :label="items.label"
        :prop="items.prop"
        :style="items.importantStyle || config?.horizontallyWidth"
      >
        <el-col :span="(config?.horizontallyWidth && 24) || items.span || 24">
          <template v-if="items.type === 'input'">
            <el-input
              v-model="ruleForm[items.prop]"
              :disabled="items.disabled"
              :placeholder="items.placeholder"
              :style="items.style"
              @change="(e:string) => items.change&&items.change(e, items.prop)||({})"
              @blur="() => (items.blur && items.blur(ruleForm[items.prop], items.prop)) || {}"
            />
          </template>
          <template v-if="items.type === 'inputNumber'">
            <el-input-number
              v-model="ruleForm[items.prop]"
              :min="items.min"
              :max="items.max"
              :step="items.step ?? 1"
              :disabled="items.disabled ?? false"
              :controls="items.controls ?? true"
              :placeholder="items.placeholder"
              :controls-position="items.position"
              :size="items.size ?? 'default'"
              :style="items.style"
              @change="(e:string) => items.change&&items.change(e, items.prop)||({})"
              @blur="() => (items.blur && items.blur(ruleForm[items.prop], items.prop)) || {}"
            />
          </template>
          <template v-if="items.type === 'number'">
            <el-input
              v-model.number="ruleForm[items.prop]"
              type="text"
              autocomplete="off"
              :maxlength="items.maxLength"
              :disabled="items.disabled ?? false"
              :size="items.size ?? 'default'"
              :placeholder="items.placeholder"
              @change="(e:string) => items.change&&items.change(e, items.prop)||({})"
              @blur="() => (items.blur && items.blur(ruleForm[items.prop], items.prop)) || {}"
            />
          </template>
          <template v-if="items.type === 'select'">
            <el-select
              v-model="ruleForm[items.prop]"
              :disabled="items.disabled"
              :multiple="items.multiple"
              :collapse-tags="items.collapseTags"
              :filterable="items.isSearch"
              :remote="items.isSearch"
              :reserve-keyword="items.isSearch"
              :placeholder="items.placeholder"
              :remote-method="(query: string) => { remoteMethod(query, index) }"
              :style="items.style"
              clearable
              @change="(e:string) => items.change&&items.change(e, items.prop)||({})"
              @clear="selectChange(index)"
            >
              <el-option
                v-for="item in items.option"
                :key="item.label"
                :label="item.label"
                :value="item.value"
                :disabled="item.disabled"
                :class="{ bold: item.bold }"
              />
            </el-select>
          </template>
          <template v-if="items.type === 'date'">
            <el-date-picker
              v-model="ruleForm[items.prop]"
              type="date"
              :format="items.format || 'YYYY-MM-DD'"
              :value-format="items.valueFormat || 'YYYY-MM-DD'"
              :placeholder="items.placeholder"
              :style="items.style"
              @change="(e:string) => items.change&&items.change(e, items.prop)||({})"
              :disabled-date="(time: Date) => disabledDate(time, items.disabledTime)"
            />
          </template>
          <template v-if="items.type === 'switch'">
            <el-switch v-model="ruleForm[items.prop]" />
          </template>
          <template v-if="items.type === 'checkbox'">
            <el-checkbox-group v-model="ruleForm[items.prop]">
              <el-checkbox
                v-for="item in items.checkBoxOption"
                :key="item.name"
                :label="item.label"
                :name="item.name"
                @change="(e:string) => items.change&&items.change(e, items.prop)||({})"
              />
            </el-checkbox-group>
          </template>
          <template v-if="items.type === 'radio'">
            <el-radio-group
              v-model="ruleForm[items.prop]"
              @change="(e:string) => items.change&&items.change(e, items.prop)||({})"
            >
              <el-radio v-for="item in items.option" :key="item.label" :label="item.label">
                {{ item.value }}
              </el-radio>
            </el-radio-group>
          </template>
          <template v-if="items.type === 'textarea'">
            <el-input
              v-model="ruleForm[items.prop]"
              :disabled="items.disabled"
              type="textarea"
              @change="(e:string) => items.change&&items.change(e, items.prop)||({})"
              @blur="() => (items.blur && items.blur(ruleForm[items.prop], items.prop)) || {}"
            />
          </template>
        </el-col>
      </el-form-item>
    </template>

    <el-form-item v-if="!config?.hiddenBtn" :class="{ btnBox: !!config?.btnClass }">
      <div :class="config?.btnClass ? `${config.btnClass} ` : 'flr'">
        <el-button v-if="nextSubmitShow" type="primary" @click="submitForm(ruleFormRef, true)">
          Next Add
        </el-button>
        <el-button
          :class="{ reset: nextSubmitShow }"
          type="primary"
          @click="submitForm(ruleFormRef)"
        >
          {{ btnText || 'Create' }}
        </el-button>
        <el-button class="reset" @click="resetForm(ruleFormRef)">
          {{ cancelText ?? 'Reset' }}
        </el-button>
      </div>
    </el-form-item>
  </el-form>
</template>

<script lang="ts" setup>
import type { ElForm } from 'element-plus'
import { cloneDeep, debounce } from 'lodash-es'
import moment from 'moment'
import { Config, FormList, RulesITF, SelectList, DisabledTime, FormData } from './typing/form'
type FormInstance = InstanceType<typeof ElForm>

const formSize = ref('default')
const ruleFormRef = ref<FormInstance>()

interface Props {
  formList: FormList[]
  formData: FormData
  rules?: RulesITF
  config?: Config
  btnText?: string
  cancelText?: string
  nextSubmitShow?: boolean
}
const props = defineProps<Props>()
const formList = computed(() => props.formList)
const rules = computed(() => props.rules ?? {})
const ruleForm = computed(() => props.formData)
const loading = ref(false)
const selectList = ref<SelectList>({})
const emit = defineEmits([
  'submitData',
  'continueSubmit',
  'update:formData',
  'update:formList',
  'cancel',
  'getForm',
])
// formData和父组件数据同步
watchEffect(() => emit('update:formData', ruleForm.value))
// 将表单验证暴露出去
onMounted(() => {
  emit('getForm', ruleFormRef.value)
})
// 提交
const submitForm = (formEl: FormInstance | undefined, isNext?: boolean) => {
  // console.log(ruleForm.value)
  if (!formEl) return
  formEl.validate((valid) => {
    if (valid) {
      isNext ? emit('continueSubmit', ruleForm.value) : emit('submitData', ruleForm.value)
    } else {
      console.log('error submit!')
      return false
    }
  })
}
// 重置
const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.resetFields()
  emit('cancel')
}
// 获取所有原始select option值
for (const [index, item] of formList.value.entries()) {
  if (item.type === 'select') {
    Object.assign(selectList.value, {
      [index]: item.option,
    })
  }
}
// 远程搜索
// 注意：搜索选择以后再次搜索，搜索的列表是以上次搜索结果为范围的，如果要以全部的搜索结果来为范围将option改为selectList.value[index]
const remoteMethod = debounce((query: string, index: number) => {
  const data = cloneDeep(selectList.value)
  if (query) {
    loading.value = true
    loading.value = false
    const op = data[index]?.filter((item: { label: string }) => {
      return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1
    })
    formList.value[index].option = op
  } else {
    formList.value[index].option = data[index]
  }
}, 150)
// 下拉框清除按钮显示原始的option内容
const selectChange = (index: number) => {
  formList.value[index].option = selectList.value[index]
}
// 时间选择器设置时间范围
const disabledDate = (time: Date, disabledTime?: DisabledTime) => {
  if (!disabledTime) return
  const { start, during, end } = disabledTime
  // const traverseDate = time.getTime()
  // 不要用moment(new Date(start)).valueOf()和traverseDate进行对比，traverseDate是以0点计算，moment是以8点计算
  // moment(itemTime).diff(moment(traverseDate), 'days')也不行，同理
  const format = 'YYYYMMDD'
  const traverseDate = moment(time).format(format)
  let flag = false
  if (start) {
    // 开始时间
    flag = moment(new Date(start)).format(format) > traverseDate
  }
  if (during?.length && !flag) {
    // 某些时间禁用
    flag = !!during.find((item) => traverseDate === moment(new Date(item)).format(format))
  }
  if (end && !flag) {
    // 结束时间
    flag = moment(new Date(end)).format(format) < traverseDate
  }
  return flag
}
</script>
<style lang="scss" scoped>
.el-input-number {
  width: 100%;

  :deep(.el-input__inner) {
    text-align: left;
  }
}

.btnBox {
  width: 100%;
  display: flex;
  justify-content: center;

  :deep(.el-form-item__content) {
    display: flex;
    justify-content: center;
  }
}

.bold {
  font-weight: bold;
  color: #000;
}

.btnClass {
  // width: 33%;
  margin-top: 58px;

  button {
    width: 120px;
    height: 40px;
    font-size: 18px;
  }

  .reset {
    margin-left: 0;
    margin-right: 50px;
  }
}
</style>
